package com.example.timer.executor;

import com.example.timer.entity.JobInfo;
import com.example.timer.enums.ScheduleTypeEnum;
import com.example.timer.handler.IJobHandler;
import com.example.timer.handler.annotation.Job;
import com.example.timer.handler.impl.MethodJobHandler;
import com.example.timer.helper.JobScheduleHelper;
import com.example.timer.helper.JobTriggerPoolHelper;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger;

/**
 * @author daiguojun
 */
public class JobExecutor {

    private static final Logger logger = Logger.getLogger(JobExecutor.class.getName());

    private List<Object> xxlJobBeanList = new ArrayList<>();

    public List<Object> getXxlJobBeanList() {
        return xxlJobBeanList;
    }

    public void setXxlJobBeanList(List<Object> xxlJobBeanList) {
        this.xxlJobBeanList = xxlJobBeanList;
    }



    /**
     * 初始化所有的注解相关方法
     */
    public void start() {
        try {
            // init JobHandler Repository (for method)
            initJobHandlerMethodRepository(xxlJobBeanList);

            // init JobScheduleHelper 启动扫描线程
            JobScheduleHelper.getInstance().start();


            // admin trigger pool start 启动执行线程
            JobTriggerPoolHelper.toStart();
        } catch (Exception e) {
            logger.severe("程序异常终止,异常信息："+e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * job handler repository
     */
    private static ConcurrentMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();

    public static IJobHandler loadJobHandler(String name){
        return jobHandlerRepository.get(name);
    }

    /**
     * 项目启动时注册 所有执行器相关方法,目的是为了调到具体的方法
     * @param name
     * @param jobHandler
     * @return
     */
    public static IJobHandler registerJobHandler(String name, IJobHandler jobHandler){
        logger.info(">>>>>>>>>>> job register handler success, name:"+ name +", jobHandler:"+jobHandler);
        return jobHandlerRepository.put(name, jobHandler);
    }

    /**
     * job info register
     */
    private static List<JobInfo> scheduleList = new CopyOnWriteArrayList<>();

    public static List<JobInfo> loadScheduleList() {
        return scheduleList;
    }

    /**
     * 项目启动时注册 所有执行器相关方法,目的是为了把信息给到定时任务重
     * @param jobInfo
     * @return
     */
    public static void registerJobInfo(JobInfo jobInfo){
        if (jobInfo.getType() != ScheduleTypeEnum.NONE) {
            logger.info(">>>>>>>>>>> job register info success,jobInfo:"+jobInfo);
            scheduleList.add(jobInfo);
        }
    }


    private void initJobHandlerMethodRepository(List<Object> xxlJobBeanList) throws Exception {
        if (xxlJobBeanList==null || xxlJobBeanList.isEmpty()) {
            logger.severe(">>>>>>> job not config,xxlJobBeanList is empty!");
            return;
        }

        // init job handler from method
        for (Object bean: xxlJobBeanList) {
            // method
            Method[] methods = bean.getClass().getDeclaredMethods();
            if (methods==null || methods.length==0) {
                continue;
            }
            for (Method executeMethod : methods) {

                // annotation
                Job job = executeMethod.getAnnotation(Job.class);
                if (job == null) {
                    continue;
                }
                // 添加注解的属性信息
                JobInfo jobInfo = new JobInfo();
                String name = job.value();
                jobInfo.setName(name);
                jobInfo.setType(job.type());
                jobInfo.setScheduleConf(job.scheduleConf());
                // 设置下次执行时间
                jobInfo.freshNextTriggerTime(jobInfo,new Date());
                if (name.trim().length() == 0) {
                    throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
                }
                if (loadJobHandler(name) != null) {
                    throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts.");
                }


                executeMethod.setAccessible(true);

                // init and destory
                Method initMethod = null;
                Method destroyMethod = null;

                if (job.init().trim().length() > 0) {
                    try {
                        initMethod = bean.getClass().getDeclaredMethod(job.init());
                        initMethod.setAccessible(true);
                    } catch (NoSuchMethodException e) {
                        throw new RuntimeException("job method-handler initMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
                    }
                }
                if (job.destroy().trim().length() > 0) {
                    try {
                        destroyMethod = bean.getClass().getDeclaredMethod(job.destroy());
                        destroyMethod.setAccessible(true);
                    } catch (NoSuchMethodException e) {
                        throw new RuntimeException("job method-handler destroyMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
                    }
                }

                // registry job handler
                registerJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));
                // registry job info
                registerJobInfo(jobInfo);

            }

        }

    }


    public void destroy(){
        // destory JobScheduleHelper
        JobScheduleHelper.getInstance().toStop();
        // destory JobScheduleHelper
        JobTriggerPoolHelper.toStop();
        // destory jobThreadRepository
        jobHandlerRepository.clear();


    }

}
